﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace VisualStudioNativeApp
{
    class Program
    {
        // 定义目录
        private static string directoryPath = "C:\\Users\\xiehaijun\\Soft\\ssl\\gz\\ssl\\ssl";
        static void Main(string[] args)
        {
            // 项目右键 --> 属性 --> 资源 ---> 字符串进行配置 （添加图像也是这样获取） 如果需要添加新资源点击 【添加资源】
            //Console.WriteLine("配置test=" + Properties.Resources.test);


            // 读取文件，需要选择文件，点击属性--》生成操作设置成 【嵌入的资源】(如果debug，在：c:\users\xiehaijun\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\clash_template21.yaml)
            //string sDb = AppDomain.CurrentDomain.BaseDirectory + "clash_template21.yaml";
            //Console.WriteLine("目标地址="+ sDb);
            //if (!File.Exists(sDb))
            //{
            //    Assembly assembly = Assembly.GetExecutingAssembly();
            //    string resourceName = assembly.GetName().Name.ToString() + ".Resources.clash_template2.yaml";
            //    Console.WriteLine(resourceName);
            //    using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            //    {
            //        byte[] buffer = new byte[stream.Length];
            //        stream.Read(buffer, 0, buffer.Length);
            //        stream.Seek(0, SeekOrigin.Begin);
            //        using (FileStream fs = new FileStream(sDb, FileMode.Create))
            //            fs.Write(buffer, 0, buffer.Length);
            //    }

            //    Console.WriteLine($"db文件：{sDb}，不存在，已自动复制");
            //}

            // 压缩成gz
            //DirectoryInfo directorySelected = new DirectoryInfo(directoryPath);
            //CompressGz(directorySelected);
            // 解压gz
            //foreach (FileInfo fileToDecompress in directorySelected.GetFiles("*.gz"))
            //{
            //    DecompressGz(fileToDecompress);
            //}

            //CompressDirectory("C:\\Users\\xiehaijun\\Soft\\ssl\\gz\\ssl\\ssl", "C:\\Users\\xiehaijun\\Soft\\ssl\\gz\\ssl\\ssl.gz");

            string baseDir = AppDomain.CurrentDomain.BaseDirectory + "ssl";
            if (!Directory.Exists(baseDir))//如果路径不存在
            {
                Directory.CreateDirectory(baseDir);//创建一个路径的文件夹
            }

            Assembly assembly = Assembly.GetExecutingAssembly();
            // 复制bat
            string resourceBatFile = assembly.GetName().Name.ToString() + ".Resources.ssl_install.bat";
            CopyFile(resourceBatFile, baseDir + "\\ssl_install.bat", assembly);
            // 复制证书
            string crtPath = baseDir + "\\crt";
            if (!Directory.Exists(crtPath))//如果路径不存在
            {
                Directory.CreateDirectory(crtPath);//创建一个路径的文件夹
            }
            string resourceCrtFile = assembly.GetName().Name.ToString() + ".Resources.boot.pem";
            CopyFile(resourceCrtFile, crtPath + "\\boot.pem", assembly);
            // 复制cermgr.exe
            string cermgrPath = baseDir + "\\certmgr";
            if (!Directory.Exists(cermgrPath))//如果路径不存在
            {
                Directory.CreateDirectory(cermgrPath);//创建一个路径的文件夹
            }
            string resourceCermgrFile = assembly.GetName().Name.ToString() + ".Resources.certmgr.exe";
            CopyFile(resourceCermgrFile, cermgrPath + "\\certmgr.exe", assembly);

            // 开始执行脚本
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "cmd.exe",
                    //Arguments = "/c ipconfig",
                    Arguments = "/k \"" + baseDir + "\\ssl_install.bat" + "\"",
                    RedirectStandardOutput = true,//由调用程序获取输出信息
                    UseShellExecute = false, //是否使用操作系统shell启动
                    CreateNoWindow = true //不显示程序窗口
                }
            };

            process.Start();
            string output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            Console.WriteLine(output);
            process.Close();


            // 判断是否bat执行完毕
            bool fileExist = false;
            do
            {
                string filePath = cermgrPath + "\\exit";
                if (!File.Exists(filePath))
                {
                    fileExist = true;
                }
                else
                {
                    fileExist = false;
                }
                Thread.Sleep(TimeSpan.FromSeconds(1));
            } while (fileExist);

            Console.WriteLine("处理结束，请等待程序自动关闭");
            Thread.Sleep(TimeSpan.FromSeconds(3));

            // 删除目录
            try
            {
                if (Directory.Exists(baseDir))
                {
                    Directory.Delete(baseDir, true); // 第二个参数为 true，表示递归删除包括子文件夹和文件
                    //Console.WriteLine("文件夹删除成功。");
                }
                else
                {
                    //Console.WriteLine("文件夹不存在。");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("删除文件夹时出错：" + e.Message);
            }
        }

        public static void CopyFile(string resourceFile, string targetFile, Assembly assembly)
        {
            using (Stream stream = assembly.GetManifestResourceStream(resourceFile))
            {
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                stream.Seek(0, SeekOrigin.Begin);
                using (FileStream fs = new FileStream(targetFile, FileMode.Create))
                    fs.Write(buffer, 0, buffer.Length);
            }
        }

        public static void CompressGz(DirectoryInfo directorySelected)
        {
            foreach (FileInfo fileToCompress in directorySelected.GetFiles())
            {
                using (FileStream originalFileStream = fileToCompress.OpenRead())
                {
                    if ((File.GetAttributes(fileToCompress.FullName) &
                       FileAttributes.Hidden) != FileAttributes.Hidden & fileToCompress.Extension != ".gz")
                    {
                        using (FileStream compressedFileStream = File.Create(fileToCompress.FullName + ".gz"))
                        {
                            using (GZipStream compressionStream = new GZipStream(compressedFileStream,
                               CompressionMode.Compress))
                            {
                                originalFileStream.CopyTo(compressionStream);
                            }
                        }
                        FileInfo info = new FileInfo(directoryPath + Path.DirectorySeparatorChar + fileToCompress.Name + ".gz");
                        Console.WriteLine($"Compressed {fileToCompress.Name} from {fileToCompress.Length.ToString()} to {info.Length.ToString()} bytes.");
                    }
                }
            }
        }

        public static void DecompressGz(FileInfo fileToDecompress)
        {
            using (FileStream originalFileStream = fileToDecompress.OpenRead())
            {
                string currentFileName = fileToDecompress.FullName;
                string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);

                using (FileStream decompressedFileStream = File.Create(newFileName))
                {
                    using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
                    {
                        decompressionStream.CopyTo(decompressedFileStream);
                        Console.WriteLine($"Decompressed: {fileToDecompress.Name}");
                    }
                }
            }
        }

        static void CompressDirectory(string sInDir, string sOutFile)
        {
            string[] sFiles = Directory.GetFiles(sInDir, "*.*", SearchOption.AllDirectories);
            int iDirLen = sInDir[sInDir.Length - 1] == Path.DirectorySeparatorChar ? sInDir.Length : sInDir.Length + 1;

            using (FileStream outFile = new FileStream(sOutFile, FileMode.Create, FileAccess.Write, FileShare.None))
            using (GZipStream str = new GZipStream(outFile, CompressionMode.Compress))
                foreach (string sFilePath in sFiles)
                {
                    string sRelativePath = sFilePath.Substring(iDirLen);
                    CompressFile(sInDir, sRelativePath, str);
                }
        }
        static void CompressFile(string sDir, string sRelativePath, GZipStream zipStream)
        {
            //Compress file name
            char[] chars = sRelativePath.ToCharArray();
            zipStream.Write(BitConverter.GetBytes(chars.Length), 0, sizeof(int));
            foreach (char c in chars)
                zipStream.Write(BitConverter.GetBytes(c), 0, sizeof(char));

            //Compress file content
            byte[] bytes = File.ReadAllBytes(Path.Combine(sDir, sRelativePath));
            zipStream.Write(BitConverter.GetBytes(bytes.Length), 0, sizeof(int));
            zipStream.Write(bytes, 0, bytes.Length);
        }
    }
}
